<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>Web Audio API examples: MediaStreamAudioSourceNode</title>
  </head>

  <body>
    <h1>Web Audio API examples: MediaStreamAudioSourceNode</h1>
    <video controls></video>
    <br />
    <label for="gain">Volume: </label>
    <input id="gain" type="range" min="1" max="40" />

    <p>Biquad filter frequency response for:</p>
    <ul class="freq-response"></ul>
    <script>
      // Store useful UI elements
      const video = document.querySelector("video");
      const range = document.querySelector("#gain");
      const freqResponseOutput = document.querySelector(".freq-response");

      // Create float32 arrays for getFrequencyResponse()
      const frequencyArray = new Float32Array([1000, 2000, 3000, 4000, 5000]);
      const magResponseOutput = new Float32Array(frequencyArray.length);
      const phaseResponseOutput = new Float32Array(frequencyArray.length);

      navigator.mediaDevices
        .getUserMedia({ audio: true, video: true })
        .then((stream) => {
          video.srcObject = stream;
          video.onloadedmetadata = (e) => {
            video.play();
            video.muted = true;
          };

          // Create a MediaStreamAudioSourceNode
          // Feed the HTMLMediaElement into it
          const audioCtx = new AudioContext();
          const source = new MediaStreamAudioSourceNode(audioCtx, {
            mediaStream: stream,
          });

          // Create a biquadfilter
          const biquadFilter = new BiquadFilterNode(audioCtx, {
            type: "lowshelf",
            frequency: 1000,
            gain: range.value,
          });

          // Chain the nodes so we can play the
          // music and adjust the volume using the mouse cursor
          source.connect(biquadFilter);
          biquadFilter.connect(audioCtx.destination);

          // Get new mouse pointer coordinates when mouse is moved
          // then set new gain value
          range.oninput = () => {
            biquadFilter.gain.value = range.value;
          };

          // Read frequency response:

          // Get magnitude and phase associated with a frequency
          biquadFilter.getFrequencyResponse(
            frequencyArray,
            magResponseOutput,
            phaseResponseOutput
          );

          // Populate list
          for (let i = 0; i < frequencyArray.length; i++) {
            const listItem = document.createElement("li");
            listItem.textContent = `${frequencyArray[i]}Hz: Magnitude ${magResponseOutput[i]}, Phase ${phaseResponseOutput[i]}rad.`;
            freqResponseOutput.appendChild(listItem);
          }
        })
        .catch((err) => {
          console.error(`The following error occurred: ${err}`);
        });
    </script>
  </body>
</html>
